Popular Searches
Popular Course Categories
Popular Courses

Opening and closing screens

Opening and closing screens

Flutter Navigation & Screens

Flutter Opening and Closing Screens

Opening and closing screens is one of the most important concepts in Flutter application development. Most applications contain multiple screens, such as Home, Login, Products, Product Details, Profile, Settings, Cart, Checkout, and Payment.

Flutter manages these screens using routes and the Navigator. A new screen can be opened using Navigator.push(), while the current screen can be closed using Navigator.pop(). Flutter's official documentation describes screens and pages as routes managed by a Navigator stack. Flutter Navigation Basics


1. What Does Opening a Screen Mean?

Opening a screen means navigating from the current screen to another screen.

For example:

Home Screen
    ↓
Product Screen

When the user taps a button on the Home screen, Flutter can use Navigator.push() to place the Product screen on top of the navigation stack.

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const ProductScreen(),
  ),
);

2. What Does Closing a Screen Mean?

Closing a screen generally means removing the current route from the Navigator stack and returning to the previous route.

Flutter provides:

Navigator.pop(context);

For example:

Home
  ↓
Product Details
  ↓
Navigator.pop()
  ↓
Home

The pop() method removes the top-most route from the Navigator stack. Navigator.pop API


3. Understanding Flutter Routes

In Flutter, a screen is commonly represented by a Route. The Navigator manages a stack of these routes.

For example:

[Home]
[Products]
[Product Details]

The top-most route is the currently visible screen.

When the user opens Product Details:

Home
Products
Product Details <-- Current Screen

When the user closes Product Details:

Home
Products <-- Current Screen

4. Navigator Stack

The Navigator uses a stack-based navigation model.

Initial State

[Home]

After Opening Products

[Home]
[Products]

After Opening Product Details

[Home]
[Products]
[Product Details]

After Closing Product Details

[Home]
[Products]

This stack model makes forward and backward navigation straightforward.


5. Opening a Screen Using Navigator.push()

The most common way to open a new screen using the imperative Navigator API is Navigator.push().

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const SecondScreen(),
  ),
);

According to the Flutter API, push() places the supplied route on the Navigator stack and returns a Future that completes when that route is popped. Navigator.push API


6. Basic Screen Opening Example

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home Screen'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => const DetailsScreen(),
              ),
            );
          },
          child: const Text('Open Details'),
        ),
      ),
    );
  }
}

class DetailsScreen extends StatelessWidget {
  const DetailsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Details Screen'),
      ),
      body: const Center(
        child: Text('Welcome to Details Screen'),
      ),
    );
  }
}

7. Understanding the Navigator.push() Code

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const DetailsScreen(),
  ),
);
CodePurpose
NavigatorManages application routes.
push()Opens a new route.
contextIdentifies the relevant Navigator in the widget tree.
MaterialPageRouteCreates a Material-style route.
builderBuilds the destination screen.
DetailsScreen()The screen that will be opened.

8. Closing a Screen Using Navigator.pop()

Once a screen has been opened using Navigator.push(), it can normally be closed with:

Navigator.pop(context);

Example

class DetailsScreen extends StatelessWidget {
  const DetailsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Details'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: const Text('Close Screen'),
        ),
      ),
    );
  }
}

9. Opening and Closing Flow

Home Screen
     |
     | Navigator.push()
     ↓
Details Screen
     |
     | Navigator.pop()
     ↓
Home Screen

This is the basic Flutter screen navigation pattern.


10. Using Navigator.of(context)

You can also access the Navigator explicitly using Navigator.of(context).

Opening a Screen

Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => const DetailsScreen(),
  ),
);

Closing a Screen

Navigator.of(context).pop();

Navigator.of(context) retrieves the nearest Navigator associated with the supplied context. Navigator.of API


11. MaterialPageRoute

MaterialPageRoute is commonly used to create a route for Material applications.

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const ProfileScreen(),
  ),
);

The builder callback creates the widget for the destination route.


12. CupertinoPageRoute

Flutter also provides CupertinoPageRoute for Cupertino-style page transitions.

Navigator.push(
  context,
  CupertinoPageRoute(
    builder: (context) => const ProfileScreen(),
  ),
);

This can be useful when creating an iOS-style application experience.


13. Opening Multiple Screens

You can open several screens one after another.

Home
 ↓
Products
 ↓
Product Details
 ↓
Checkout

Example:

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const ProductsScreen(),
  ),
);

From Products:

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const ProductDetailsScreen(),
  ),
);

From Product Details:

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const CheckoutScreen(),
  ),
);

The stack becomes:

[Home]
[Products]
[Product Details]
[Checkout]

14. Closing Multiple Screens

Calling Navigator.pop() normally removes only the top-most route.

Navigator.pop(context);

For example:

Before:
[Home]
[Products]
[Details]

After one pop:
[Home]
[Products]

To remove multiple routes based on a condition, Flutter provides popUntil().

Navigator.popUntil(
  context,
  (route) => route.isFirst,
);

15. Opening a Screen and Passing Data

Often, the destination screen needs information from the current screen.

For example, a Product List screen can send product information to Product Details.

Product Model

class Product {
  final String name;
  final double price;

  const Product({
    required this.name,
    required this.price,
  });
}

Open Details Screen

final product = Product(
  name: 'Laptop',
  price: 60000,
);

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => ProductDetailsScreen(
      product: product,
    ),
  ),
);

Receive Data

class ProductDetailsScreen extends StatelessWidget {
  final Product product;

  const ProductDetailsScreen({
    super.key,
    required this.product,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(product.name),
      ),
      body: Center(
        child: Text(
          'Price: ₹${product.price}',
        ),
      ),
    );
  }
}

Flutter's navigation cookbook documents passing data to a new screen through route navigation. Send data to a new screen


16. Closing a Screen and Returning Data

A screen can return a value when it is closed.

Navigator.pop(context, 'Flutter');

The screen that opened it can receive that value:

final result = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const SelectionScreen(),
  ),
);

The Future returned by push() completes with the result passed to pop(). Navigator.push API


17. Complete Example of Opening, Closing, and Returning Data

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State createState() => _HomeScreenState();
}

class _HomeScreenState extends State {
  String result = 'No selection';

  Future openSelectionScreen() async {
    final selected = await Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => const SelectionScreen(),
      ),
    );

    if (!mounted) return;

    setState(() {
      result = selected ?? 'No selection';
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Selected: $result',
              style: const TextStyle(fontSize: 20),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: openSelectionScreen,
              child: const Text('Open Selection'),
            ),
          ],
        ),
      ),
    );
  }
}

class SelectionScreen extends StatelessWidget {
  const SelectionScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Select Option'),
      ),
      body: Column(
        children: [
          ListTile(
            title: const Text('Flutter'),
            onTap: () {
              Navigator.pop(context, 'Flutter');
            },
          ),
          ListTile(
            title: const Text('Dart'),
            onTap: () {
              Navigator.pop(context, 'Dart');
            },
          ),
        ],
      ),
    );
  }
}

18. Opening a Screen with a Button

A very common pattern is opening a screen when a user presses a button.

ElevatedButton(
  onPressed: () {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => const ProfileScreen(),
      ),
    );
  },
  child: const Text('Open Profile'),
)

19. Opening a Screen from a ListTile

Navigation is also commonly triggered when a user taps a ListTile.

ListTile(
  leading: const Icon(Icons.person),
  title: const Text('Profile'),
  trailing: const Icon(Icons.arrow_forward_ios),
  onTap: () {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => const ProfileScreen(),
      ),
    );
  },
)

20. Opening a Screen from an IconButton

IconButton(
  icon: const Icon(Icons.settings),
  onPressed: () {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => const SettingsScreen(),
      ),
    );
  },
)

21. Closing a Screen with AppBar Back Button

When a route is pushed and the screen uses a typical Scaffold and AppBar, Flutter can provide a back button automatically when appropriate.

Scaffold(
  appBar: AppBar(
    title: const Text('Details'),
  ),
  body: const Center(
    child: Text('Details Screen'),
  ),
)

The back button normally performs the equivalent of popping the current route. Flutter's Navigator documentation notes that an AppBar can automatically add a back button for navigating to an earlier route. Navigator Documentation


22. Creating a Custom Close Button

You can manually create a button to close the current screen.

IconButton(
  icon: const Icon(Icons.close),
  onPressed: () {
    Navigator.pop(context);
  },
)

Or:

ElevatedButton(
  onPressed: () {
    Navigator.pop(context);
  },
  child: const Text('Close'),
)

23. Checking Whether a Screen Can Be Closed

Before calling pop(), you can check whether the Navigator has a route that can be popped.

if (Navigator.canPop(context)) {
  Navigator.pop(context);
}

Navigator.canPop() returns whether popping would remove something other than the initial route. Navigator.canPop API


24. Navigator.pop() vs Closing the Entire Application

Navigator.pop(context) normally closes the current route. It does not mean "exit the application".

Navigator.pop(context);

For example:

Home
  ↓
Details
  ↓
Navigator.pop()
  ↓
Home

It is therefore important to distinguish between closing a screen and terminating an application instance.


25. Opening a Login Screen

Suppose an application starts with a login screen.

Login Screen
     ↓
Home Screen

After successful login, the application can open Home:

Navigator.pushReplacement(
  context,
  MaterialPageRoute(
    builder: (context) => const HomeScreen(),
  ),
);

pushReplacement() replaces the current route rather than simply adding another route to the stack.


26. Why Use pushReplacement() for Login?

If Login is pushed normally:

[Login]
[Home]

Pressing Back from Home could return to Login.

With replacement:

[Home]

The Login route has been replaced.

Navigator.pushReplacement(
  context,
  MaterialPageRoute(
    builder: (context) => const HomeScreen(),
  ),
);

27. Opening and Closing a Dialog

Dialogs are also presented as routes in Flutter's navigation system.

showDialog(
  context: context,
  builder: (context) {
    return AlertDialog(
      title: const Text('Confirmation'),
      content: const Text(
        'Do you want to continue?',
      ),
      actions: [
        TextButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: const Text('Cancel'),
        ),
      ],
    );
  },
);

Here, Navigator.pop(context) closes the dialog.


28. Returning a Result from a Dialog

final confirmed = await showDialog(
  context: context,
  builder: (context) {
    return AlertDialog(
      title: const Text('Delete Item'),
      content: const Text(
        'Are you sure you want to delete this item?',
      ),
      actions: [
        TextButton(
          onPressed: () {
            Navigator.pop(context, false);
          },
          child: const Text('Cancel'),
        ),
        ElevatedButton(
          onPressed: () {
            Navigator.pop(context, true);
          },
          child: const Text('Delete'),
        ),
      ],
    );
  },
);

if (confirmed == true) {
  print('Item deleted');
}

29. Opening a Modal Bottom Sheet

A modal bottom sheet can also be used to present temporary content.

showModalBottomSheet(
  context: context,
  builder: (context) {
    return SizedBox(
      height: 200,
      child: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: const Text('Close'),
        ),
      ),
    );
  },
);

Inside the bottom sheet, Navigator.pop(context) closes the sheet.


30. Opening Screens in an E-Commerce Application

A typical e-commerce application might have the following flow:

Home
  ↓
Products
  ↓
Product Details
  ↓
Cart
  ↓
Checkout
  ↓
Payment
  ↓
Order Success

Each transition can use an appropriate Navigator operation.

ActionCommon Method
Home → Productspush()
Products → Product Detailspush()
Product Details → Productspop()
Login → HomepushReplacement()
Checkout → Home after completionpushAndRemoveUntil()
Return to first routepopUntil()

31. Opening and Closing Profile Screens

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home'),
        actions: [
          IconButton(
            icon: const Icon(Icons.person),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) =>
                      const ProfileScreen(),
                ),
              );
            },
          ),
        ],
      ),
      body: const Center(
        child: Text('Home'),
      ),
    );
  }
}

class ProfileScreen extends StatelessWidget {
  const ProfileScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Profile'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: const Text('Close Profile'),
        ),
      ),
    );
  }
}

32. Opening Settings from Profile

ListTile(
  leading: const Icon(Icons.settings),
  title: const Text('Settings'),
  onTap: () {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => const SettingsScreen(),
      ),
    );
  },
)

The navigation stack becomes:

[Home]
[Profile]
[Settings]

Pressing Back from Settings:

[Home]
[Profile]

Pressing Back again:

[Home]

33. Closing Multiple Screens with popUntil()

Suppose the application has:

[Home]
[Products]
[Details]
[Checkout]

If the user wants to return directly to Home:

Navigator.popUntil(
  context,
  (route) => route.isFirst,
);

The result is:

[Home]

Flutter's navigation cookbook describes popUntil() as repeatedly removing recent routes until a supplied condition is satisfied. Flutter Navigation Basics


34. Closing Screens After Successful Checkout

Consider:

Home
Products
Cart
Checkout
Payment
Success

After successful payment, the user may need to return to Home while removing the checkout flow.

Navigator.pushAndRemoveUntil(
  context,
  MaterialPageRoute(
    builder: (context) => const HomeScreen(),
  ),
  (route) => false,
);

This pushes Home and removes previous routes according to the supplied predicate. Navigator.pushAndRemoveUntil API


35. Opening a Screen with Named Routes

Flutter also supports named routes.

MaterialApp(
  routes: {
    '/': (context) => const HomeScreen(),
    '/profile': (context) => const ProfileScreen(),
    '/settings': (context) => const SettingsScreen(),
  },
);

Open Profile:

Navigator.pushNamed(
  context,
  '/profile',
);

Close Profile:

Navigator.pop(context);

Named routes are still supported, but current Flutter documentation does not recommend them for most new applications. For many new applications, Flutter recommends Navigator with MaterialPageRoute or a routing package such as go_router, especially when advanced navigation and deep linking are required. Flutter Navigation and Routing


36. Opening Screens with go_router

For larger applications, a routing package such as go_router can provide a structured navigation system.

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

final router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomeScreen(),
    ),
    GoRoute(
      path: '/profile',
      builder: (context, state) => const ProfileScreen(),
    ),
  ],
);

void main() {
  runApp(
    MaterialApp.router(
      routerConfig: router,
    ),
  );
}

Navigate:

context.go('/profile');

For complex routing requirements, Flutter's navigation documentation recommends considering a routing package such as go_router. Flutter Navigation and Routing


37. Passing Data While Opening a Screen

Suppose the Home screen needs to open a user profile.

class User {
  final String name;
  final String email;

  const User({
    required this.name,
    required this.email,
  });
}

Open Profile:

final user = User(
  name: 'Rahul',
  email: '[email protected]',
);

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => ProfileScreen(
      user: user,
    ),
  ),
);

Receive the user:

class ProfileScreen extends StatelessWidget {
  final User user;

  const ProfileScreen({
    super.key,
    required this.user,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(user.name),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(user.name),
          Text(user.email),
        ],
      ),
    );
  }
}

38. Returning Data When Closing a Screen

For example, an Edit Profile screen can return a success message.

Navigator.pop(
  context,
  'Profile updated successfully',
);

The previous screen can receive it:

final message = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const EditProfileScreen(),
  ),
);

if (!mounted) return;

if (message != null) {
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(
      content: Text(message),
    ),
  );
}

Flutter's official cookbook demonstrates this push-and-return-data pattern. Return data from a screen


39. Screen Opening and Closing with Forms

Forms are commonly opened as separate screens.

ElevatedButton(
  onPressed: () async {
    final saved = await Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => const AddUserScreen(),
      ),
    );

    if (!mounted) return;

    if (saved == true) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('User saved successfully'),
        ),
      );
    }
  },
  child: const Text('Add User'),
)

After saving:

Navigator.pop(context, true);

40. Navigation Stack Visualization

START
  |
  v
+---------+
|  Home   |
+---------+
     |
     | push()
     v
+---------+
| Details |
+---------+
     |
     | push()
     v
+---------+
| Settings|
+---------+
     |
     | pop()
     v
+---------+
| Details |
+---------+
     |
     | pop()
     v
+---------+
|  Home   |
+---------+

41. Difference Between Opening and Closing

Opening ScreenClosing Screen
Uses Navigator.push()Uses Navigator.pop()
Adds a routeRemoves the current route
Moves forward in navigationMoves backward in navigation
Creates a new visible screenReveals the previous screen
Returns a FutureCan provide a result

42. push() and pop() with Return Values

The relationship can be represented as:

Home Screen
    |
    | push()
    v
Selection Screen
    |
    | pop('Flutter')
    v
Home Screen
    |
    | Future receives 'Flutter'

Code:

final result = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const SelectionScreen(),
  ),
);

print(result);

On the selection screen:

Navigator.pop(context, 'Flutter');

43. Important Navigation Methods

MethodPurpose
push()Opens a new route.
pop()Closes the current route.
pushReplacement()Replaces the current route.
pushAndRemoveUntil()Pushes a route and removes previous routes according to a condition.
popUntil()Removes routes until a condition is met.
popAndPushNamed()Pops the current named route and pushes another named route.
canPop()Checks whether the Navigator can pop.

44. Common Mistakes

Mistake 1: Forgetting to Use Navigator.push()

Simply creating a screen widget does not automatically display it.

const DetailsScreen();

The widget must be displayed through the appropriate widget tree or navigation mechanism.

Mistake 2: Using pop() Without a Previous Route

Before manually popping, consider:

Navigator.canPop(context)

Mistake 3: Pushing the Same Screen Repeatedly

Repeated pushes can create multiple copies of the same route in the stack.

Mistake 4: Ignoring Returned Data

If a screen returns data, use the Future returned by Navigator.push() when that result is needed.

Mistake 5: Updating State After Await Without Checking Mount Status

final result = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const DetailsScreen(),
  ),
);

if (!mounted) return;

45. Best Practices

  • Use Navigator.push() to open a new screen in a stack-based navigation flow.
  • Use Navigator.pop() to close the current screen.
  • Use MaterialPageRoute for straightforward Material navigation.
  • Pass strongly typed data through screen constructors when appropriate.
  • Use the Future returned by push() when a screen needs to return data.
  • Use pushReplacement() when the current route should be replaced.
  • Use pushAndRemoveUntil() when previous navigation history needs to be cleared according to a condition.
  • Use popUntil() to return to an earlier route in the stack.
  • Use Navigator.canPop() before custom pop operations when necessary.
  • Check mounted after awaiting navigation results before updating state.
  • Keep navigation code organized as the application grows.
  • For complex routing and deep-linking requirements, consider Router-based navigation or go_router.

46. Practical Project Example: Student Application

Consider a learning application with the following navigation:

Home
 |
 +-- Courses
 |     |
 |     +-- Course Details
 |            |
 |            +-- Lessons
 |
 +-- Profile
 |     |
 |     +-- Edit Profile
 |
 +-- Settings

Open Course Details

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const CourseDetailsScreen(),
  ),
);

Open Lessons

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const LessonsScreen(),
  ),
);

Close Lessons

Navigator.pop(context);

Close Course Details

Navigator.pop(context);

47. Complete Mini Project

import 'package:flutter/material.dart';

void main() {
  runApp(const NavigationDemo());
}

class NavigationDemo extends StatelessWidget {
  const NavigationDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
        ),
        useMaterial3: true,
      ),
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State createState() => _HomeScreenState();
}

class _HomeScreenState extends State {
  String message = 'No result';

  Future openDetails() async {
    final result = await Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => const DetailsScreen(),
      ),
    );

    if (!mounted) return;

    setState(() {
      message = result ?? 'No result';
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              message,
              style: const TextStyle(fontSize: 20),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: openDetails,
              child: const Text('Open Details'),
            ),
          ],
        ),
      ),
    );
  }
}

class DetailsScreen extends StatelessWidget {
  const DetailsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Details'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              'Details Screen',
              style: TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(
                  context,
                  'Returned from Details',
                );
              },
              child: const Text('Close and Return Data'),
            ),
            const SizedBox(height: 10),
            TextButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: const Text('Close'),
            ),
          ],
        ),
      ),
    );
  }
}

48. Execution Flow of the Mini Project

  1. The application starts on HomeScreen.
  2. The user sees the Open Details button.
  3. The button calls Navigator.push().
  4. DetailsScreen is added to the Navigator stack.
  5. The Details screen becomes visible.
  6. The user can close it with Navigator.pop().
  7. The user can also return a value using Navigator.pop(context, result).
  8. The Future returned by Navigator.push() receives that value.
  9. The Home screen can then display the returned result.

49. Opening and Closing Screen Diagram

+----------------+
|   Home Screen  |
+----------------+
        |
        | Navigator.push()
        ↓
+----------------+
| Details Screen |
+----------------+
        |
        | Navigator.pop()
        ↓
+----------------+
|   Home Screen  |
+----------------+

50. Interview Questions

Q1. How do you open a new screen in Flutter?

Use Navigator.push() with a route such as MaterialPageRoute.

Q2. How do you close the current screen?

Use Navigator.pop(context).

Q3. What is a route?

A route represents a screen or page managed by the Navigator.

Q4. What happens when Navigator.push() is called?

A new route is added to the Navigator stack and displayed above the current route.

Q5. What happens when Navigator.pop() is called?

The top-most route is removed, revealing the route underneath it.

Q6. Can Navigator.pop() return data?

Yes.

Navigator.pop(context, 'Flutter');

Q7. How does the previous screen receive the returned value?

It can await the Future returned by Navigator.push().

final result = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const DetailsScreen(),
  ),
);

Q8. What is pushReplacement()?

It replaces the current route with a new route.

Q9. What is popUntil()?

It repeatedly pops routes until a specified condition is satisfied.

Q10. What is pushAndRemoveUntil()?

It pushes a new route and removes previous routes according to a supplied predicate.


51. Practice Exercises

  1. Create a Home screen and About screen.
  2. Open About using Navigator.push().
  3. Close About using Navigator.pop().
  4. Create Product List and Product Details screens.
  5. Pass product information to Product Details.
  6. Return a selected value from Product Details.
  7. Create Login and Home screens using pushReplacement().
  8. Create Home, Cart, Checkout, and Success screens.
  9. Use pushAndRemoveUntil() after completing checkout.
  10. Use popUntil() to return to Home.
  11. Create a confirmation dialog that returns a Boolean result.
  12. Create a Profile screen with a Settings screen.
  13. Test opening and closing several screens in sequence.

52. Quick Revision

ConceptPurpose
RouteRepresents a screen/page in Flutter navigation.
NavigatorManages a stack of routes.
push()Opens a new route.
pop()Closes the current route.
pushReplacement()Replaces the current route.
pushAndRemoveUntil()Pushes a route and removes previous routes according to a condition.
popUntil()Pops routes until a condition is satisfied.
canPop()Checks whether the Navigator can pop.
MaterialPageRouteCreates a Material-style route.
CupertinoPageRouteCreates a Cupertino-style route.

53. Key Takeaways

  • Flutter screens are commonly represented as routes.
  • The Navigator manages routes using a navigation stack.
  • Navigator.push() is used to open a new screen.
  • Navigator.pop() is used to close the current screen.
  • Navigator.push() returns a Future that can receive a result from Navigator.pop().
  • Data can be passed to a new screen through constructor parameters or other routing mechanisms.
  • pushReplacement() is useful when the current route should be replaced.
  • pushAndRemoveUntil() can be used to clear previous routes according to a condition.
  • popUntil() can return the user to an earlier point in the navigation stack.
  • Navigator.canPop() can be used to check whether a route can be popped.
  • Dialogs and modal flows can also use Navigator-based popping to close and return results.
  • For advanced navigation and deep-linking requirements, Flutter supports Router-based navigation and packages such as go_router.

54. Useful Resources

Flutter Navigation and Routing: Official Flutter Navigation Documentation

Navigate to a New Screen and Back: Flutter Navigation Basics

Navigator API: Official Navigator API

Navigator.push API: Navigator.push Documentation

Navigator.pop API: Navigator.pop Documentation

Passing Data: Send Data to a New Screen

Returning Data: Return Data from a Screen

JustAcademy Flutter Training: JustAcademy Flutter Training Course

Register for Flutter Course Demo: Register for Flutter Course Demo

whatsapp